repo/checkout: Verify early if src/destination are on same device
authorColin Walters <walters@verbum.org>
Mon, 6 Mar 2017 19:51:14 +0000 (14:51 -0500)
committerAtomic Bot <atomic-devel@projectatomic.io>
Mon, 6 Mar 2017 20:58:04 +0000 (20:58 +0000)
At least in all Linux kernels up to today, one can never `link()` across
devices, so we might as well verify that up front. This will help for a future
patch to add a new type of union-add checkout, since Linux checks for `EEXIST`
before `EXDEV`.

Closes: #714
Approved by: jlebon

src/libostree/ostree-repo-checkout.c
tests/test-rofiles-fuse.sh

index 9a1516464ca3466940819a745651f5ef840b508b..50bc7030db57fee4b12b2fa37791a72a6a351928 100644 (file)
@@ -641,6 +641,8 @@ checkout_tree_at (OstreeRepo                        *self,
   gboolean did_exist = FALSE;
   glnx_fd_close int destination_dfd = -1;
   int res;
+  struct stat repo_dfd_stat;
+  struct stat destination_stat;
   g_autoptr(GVariant) xattrs = NULL;
   g_autoptr(GFileEnumerator) dir_enum = NULL;
 
@@ -666,6 +668,25 @@ checkout_tree_at (OstreeRepo                        *self,
                        &destination_dfd, error))
     goto out;
 
+  if (fstat (self->repo_dir_fd, &repo_dfd_stat) < 0)
+    {
+      glnx_set_error_from_errno (error);
+      goto out;
+    }
+  if (fstat (destination_dfd, &destination_stat) < 0)
+    {
+      glnx_set_error_from_errno (error);
+      goto out;
+    }
+
+  if (options->no_copy_fallback && repo_dfd_stat.st_dev != destination_stat.st_dev)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Unable to do hardlink checkout across devices (src=%lu destination=%lu)",
+                   repo_dfd_stat.st_dev, destination_stat.st_dev);
+      goto out;
+    }
+
   /* Set the xattrs now, so any derived labeling works */
   if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
     {
index 4dfec5145a5f3eb147c37aef672cd23dfc60319f..56045c610240bb6fe6bbd5dfd941f45a31a7bf9b 100755 (executable)
@@ -78,6 +78,6 @@ assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse anewf
 if ${CMD_PREFIX} ostree --repo=repo checkout -UH test2 mnt/test2-checkout-copy-hardlinked 2>err.txt; then
     assert_not_reached "Checking out via hardlinks across mountpoint unexpectedly succeeded!"
 fi
-assert_file_has_content err.txt "Invalid cross-device link"
+assert_file_has_content err.txt "Unable to do hardlink checkout across devices"
 
 echo "ok checkout copy fallback"